﻿using GpuHud;
using System;
using System.Collections.Generic;
using GpuHud.Settings;
using TMPro;
using UnityEditor;
using UnityEngine;
using XLua;
using Yoozoo.Framework.Core;
using Yoozoo.Managers.ResourceManagerV2.Runtime;

/*
    Facade用于简化调用接口: 如 facade.instance.Play(TYPE.FLYTEXT,PARAM)
     
     */

public enum GpuHudEntityType
{
    None = -1,
    FlyText = 1,
    PlayerName = 2,
}

/// <summary>
/// 非Mono方式管理
/// </summary>
public partial class GpuHudFacade : SingletonMono<GpuHudFacade>
{
    
    
    public static GpuHudFacade GpuFacade
    {
        get
        {
            GpuHudFacade facadeInstance = GetInstance("GpuHud");
            if (!facadeInstance.IsInitialized())
            {
                facadeInstance.Initialize();
            }
            return facadeInstance;
        }
    }

    #region 参数
    public GpuHudManagerPool GpuHudManagerPool{
        get
        {
            return gpuHudManagerPool;
        }
    }
    private GpuHudManagerPool gpuHudManagerPool;
    /// <summary>
    /// 全局配置
    /// </summary>
    private GpuHudSettings settings;

    public GpuHudSettings Settings
    {
        get
        {
            return settings;
        }
    }
    /// <summary>
    /// 延时加载列表(资源)
    /// </summary>
    private Dictionary<GpuHudEntityType, Dictionary<int,GpuHudAsset>> entityTypeMapper;
    /// <summary>
    /// 运行中的Hud实体的引用
    /// </summary>
    private EntityLinkedSetList entityReference;

    [SerializeField]
    private int entityRefCount;
    private bool isInit = false;

    public Camera m_hudCamera;
    public Camera HudCamera
    {
        get
        {
            if(m_hudCamera == null)
            {
                var cameraObject = GameObject.FindWithTag("WorldCamera");
                if(cameraObject != null)
                {
                    var hudCamera = cameraObject.transform.Find("HudCamera");
                    if (hudCamera != null)
                    {
                        m_hudCamera = hudCamera.gameObject.GetComponent<Camera>();
                    }
                }
            }

            return m_hudCamera;
        }
    }

    public int drawLayer;

    public int entityCount;

    private string normalTmpAssetName, damageTmpAssetName;

    public string NormalTmpAssetName
    {
        get { return normalTmpAssetName; }
    }
    
    public string DamageTmpAssetName
    {
        get { return damageTmpAssetName; }
    }
    
    public static Action<string, Action<TMP_FontAsset>> localizationProvider;

    private GpuHudFacadeContext m_context;

    public GpuHudFacadeContext Context
    {
        get
        {
            return m_context;
        }
    }
    #endregion

    #region Unity生命周期

    /// <summary>
    /// Update中收集Entity数据
    /// LateUpdate中对Entity进行Update
    /// 具体Update方法放在Entity中自行实现
    /// 具体来说:  
    /// GpuHudEntity本身的生命周期应该交给某个物体进行管理
    /// 包括HudEntity的参数更新也应该交给某个物体进行管理
    /// 
    /// 同时Dispose方法会标记当前Entity是否删除,如果删除的话,在一次遍历时从链表中删除引用,不执行LateUpdate
    /// 这里的Entity没有考虑使用池化,池化可以直接在GetHudEntity中实现
    /// </summary>
    private void LateUpdate()
    {
        //todo: 可以在这里进行视椎体剔除(直接SetOffScreen即可,不需要Dispose())
        int realUpdateCnt = 0;
        if (!isInit) return;
        entityRefCount = entityReference.Count;
        GpuHudEntityBase curEntity = entityReference.head;
        GpuHudEntityBase nextEntity = entityReference.head;
        while (curEntity != null)
        {
            nextEntity = curEntity.nextEntity;
            if (curEntity.removeDirty)
            {
                entityReference.Remove(curEntity);
            }
            else
            {
                if (curEntity.IsInitialize)
                {
                    realUpdateCnt++;
                    curEntity.OnLateUpdate();
                }
            }
            curEntity = nextEntity;
        }

        //Debug.LogError("RealLateUpdate次数: " + realUpdateCnt.ToString() + " 删除次数: " + removeCnt.ToString() + " 链表数量: " + entityReference.Count.ToString());

        gpuHudManagerPool.LateUpdate();
    }


    private void OnDestroy()
    {
        gpuHudManagerPool?.OnDestroy();
        if (entityReference.Count > 0)
        {
            GpuHudEntityBase curEntity = entityReference.head;
            while (curEntity != null)
            {
                curEntity?.TryDispose();
                curEntity = curEntity.nextEntity;
            }

        }
        entityReference.Dispose();
        GpuHudUtility.DisposeHook();
    }

    public Camera editorCamera;
    public int editorRenderLayer;
    public bool editorMode = false;
    private bool isPause = false;
#if UNITY_EDITOR
    
    void OnEditorPause(PauseState pause)
    {
        isPause = (pause == PauseState.Paused) ? true : false;
    }

    private void OnEditorUpdate()
    {
        /*if (isPause)
        {
            gpuHudManagerPool?.LateUpdate(true);
        }*/
    }
#endif
    #endregion

    #region 控件生命周期

    public override void Initialize(Options options = null)
    {
        base.Initialize(options);

        UMTResource.LoadAssetRapid(GpuHudSettings.DefaultResourcePath, (assetName, asset, duration, data) =>
            {
                settings = asset as GpuHudSettings;
                settings.InitRuntime();
                entityCount = 0;
                OnSettingsInit();
                OnContextInit();
                entityReference = EntityLinkedSetList.GetList();
                gpuHudManagerPool = new GpuHudManagerPool();
                gpuHudManagerPool.Init();
                drawLayer = LayerMask.NameToLayer("MarchHud");
                isInit = true;

#if UNITY_EDITOR
                EditorApplication.pauseStateChanged += OnEditorPause;
                EditorApplication.update += OnEditorUpdate;
#endif
            },
            (assetName, status, message, data) =>
            {
                Debug.LogError("Error,Please check if the GpuHudSettings.asset exists.");
            });
    }

    /// <summary>
    /// 初始化配置
    /// </summary>
    private void OnSettingsInit()
    {
        entityTypeMapper = new Dictionary<GpuHudEntityType, Dictionary<int, GpuHudAsset>>();
    }

    private void OnContextInit()
    {
        m_context = new GpuHudFacadeContext();
        //因为兼容性,考虑GpuInstance(其实可以检查Shader是否能使用来决定是否使用SSBO)
        m_context.SetRenderMethod(RenderMethod.GpuInstance);
    }
    #endregion

    #region 资源相关
    /// <summary>
    /// 当GpuHudAsset资源使用时触发,主要用来管理GpuHudAsset
    /// 当GpuHudAsset的计数器二次置为0时,会自动销毁
    /// </summary>
    /// <param name="entityType"></param>
    /// <param name="id"></param>
    /// <param name="asset"></param>
    public void OnAssetInit(GpuHudEntityType entityType,int id,GpuHudAsset asset)
    {
        if(entityTypeMapper.TryGetValue(entityType,out Dictionary<int, GpuHudAsset> assetList))
        {
            if (!assetList.TryGetValue(id,out GpuHudAsset hudAsset))
            {
                assetList[id] = asset;
                asset.OnInit(id);
            }
        }
        else
        {
            entityTypeMapper.Add(entityType, new Dictionary<int, GpuHudAsset>());
            entityTypeMapper[entityType][id] = asset;
            asset.OnInit(id);
        }
    }

    [BlackList]
    public GpuHudAsset GetAsset(GpuHudEntityType entityType, int id)
    {
        GpuHudAsset tempAsset = null;
        if (entityTypeMapper.ContainsKey(entityType))
        {
            entityTypeMapper[entityType].TryGetValue(id,out tempAsset);
        }
        return tempAsset;
    }

    /// <summary>
    /// 卸载资源
    /// </summary>
    /// <param name="entityType"></param>
    /// <param name="id"></param>
    [BlackList]
    public void DisposeAsset(GpuHudEntityType entityType, int id)
    {
        /*现在加载API都是异步的,暂时先隐藏瓢字资源丢弃方式
        if (entityTypeMapper.ContainsKey(entityType))
        {
            entityTypeMapper[entityType].Remove(id);
        }
        */
    }
    [BlackList]
    public void RegisterEntityReference(GpuHudEntityBase entity)
    {
        if(entity.isRunning || entity == null || entity.IsInitialize)
        {
            //todo: 出错
            return;
        }
        //Debug.LogError("添加entity到运行列表:  " + entity.GetHashCode());
        entityReference.AddLast(entity);
    }
    [BlackList]
    public void UnRegisterEntityReference(GpuHudEntityBase entity)
    {
        if (entity == null)
        {
            //todo: 出错
            return;
        }
        entity.removeDirty = true;
    }
    
    /*
     * 多语言部分
     */

    //设置默认的TMP资源名字
    //如果默认TMP资源发生变更,代表多语言改变(只会在多语言改变时触发)
    //就释放所有的文字
    [LuaCallCSharp]
    public void SetDefaultTMPName(string normal,string damage,bool isLocalizationChanged)
    {
        if (normal != normalTmpAssetName)
        {
            normalTmpAssetName = normal;
            damageTmpAssetName = damage;
            //多语言发生改变,执行多语言Entity的Accessor释放
        }
        
        if(isLocalizationChanged){
            foreach (var kv in entityTypeMapper)
            {
                if (kv.Value != null)
                {
                    foreach (var secKv in kv.Value)
                    {
                        if (secKv.Value != null && secKv.Value.IsLocalization())
                        {
                            secKv.Value.SetLocalizationDirty();
                        }
                    }
                }
            }
        }
    }
    
    [LuaCallCSharp]
    public void SetGpuHudAsset(List<GpuHudAsset> assets, List<int> idSet)
    {
        int cnt = 0;
        foreach (var asset in assets)
        {
            OnAssetInit(asset.m_entityType, idSet[cnt++], asset);
        }
    }
    
    [LuaCallCSharp]
    public void DisposeGpuHudAsset()
    {
        if (entityReference.Count > 0)
        {
            GpuHudEntityBase curEntity = entityReference.head;
            while (curEntity != null)
            {
                curEntity?.TryDispose();
                curEntity = curEntity.nextEntity;
            }
        }
        entityReference.Clear();
        foreach (var mapper in entityTypeMapper)
        {
            foreach (var ast in mapper.Value)
            {
                ast.Value.ClearEntityRef();
            }
        }
        entityTypeMapper.Clear();
        DisposePool();
    }
    
    /// <summary>
    /// 获取渲染组的参数
    /// </summary>
    /// <param name="groupType"></param>
    /// <returns></returns>
    public MaterialParamsSetting GetMatParamsByGroup(MatGroupType groupType)
    {
        return settings.mapGroup[settings.matGroupMap[groupType]];
    }
    
    #endregion
}
